package cn.pid21.client;

import cn.pid21.client.exception.DataReportClientException;
import cn.pid21.client.model.DataReportClientConfig;
import cn.pid21.client.request.DataReportRequest;
import cn.pid21.client.tls.PidHostnameVerifier;
import cn.pid21.client.tls.PidTrustManager;
import cn.pid21.client.util.ConfigUtil;
import lombok.Getter;
import lombok.ToString;
import okhttp3.OkHttpClient;
import okhttp3.Response;

import java.io.IOException;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * PID 客户端 - 线程安全,封装 OkHttpClient 3.x
 *
 * @author 李世坚
 * @version 1.0.0
 * <b>Creation Time:</b> 2019/8/8
 */

@Getter
@ToString
public final class DataReportClient<T extends DataReportRequest> {

    /**
     * PidClient
     */
    @SuppressWarnings("rawtypes")
    private volatile static DataReportClient dataReportClient;
    /**
     * OkHttpClient
     */
    private OkHttpClient okHttpClient;
    /**
     * PID 客户端请求信息
     */
    private T pidRequest;

    /**
     * 客户端 ID
     */
    private String clientId;

    /**
     * 客户端秘钥
     */
    private String secret;

    /**
     * 私有构造方法
     */
    private DataReportClient() {

    }

    /**
     * 私有构造方法,通过 create 方法创建客户端实例,初始化 OkHttpClient
     *
     * @param clientId 客户端ID
     * @param secret   秘钥
     */
    private DataReportClient(String clientId, String secret) {
        if (clientId.isEmpty() || secret.isEmpty()) {
            throw new DataReportClientException("clientId & secret is empty");
        }
        this.clientId = clientId;
        this.secret = secret;
        //加载配置文件
        DataReportClientConfig config = ConfigUtil.load();
        //创建 PidTrustManager 实例
        PidTrustManager pidTrustManager = new PidTrustManager();
        // 创建 OkHttpClient 实例
        okHttpClient = new OkHttpClient.Builder().connectTimeout(config.getConnectTimeout(), TimeUnit.SECONDS)
            .writeTimeout(config.getWriteTimeout(), TimeUnit.SECONDS)
            .readTimeout(config.getReadTimeout(), TimeUnit.SECONDS)
            //.sslSocketFactory(SSLSocketUtil.createSSLSocketFactory(pidTrustManager), pidTrustManager)
            .hostnameVerifier(new PidHostnameVerifier())
            //.addInterceptor(new SignInterceptor())
            .build();
    }

    /**
     * 创建 PidClient 实例
     *
     * @return PidClient
     */
    @SuppressWarnings("rawtypes")
    public static DataReportClient create(String clientId, String secret) {
        if (dataReportClient == null) {
            synchronized (DataReportClient.class) {
                if (dataReportClient == null) {
                    dataReportClient = new DataReportClient(clientId, secret);
                }
            }
        }
        return dataReportClient;
    }

    /**
     * 创建 PidClient 实例
     *
     * @param request PidRequest
     * @return PidClient
     */
    @SuppressWarnings("rawtypes")
    public DataReportClient request(T request) {
        this.pidRequest = request;
        return this;
    }

    /**
     * 执行请求
     *
     * @return 服务端返回数据 json 格式
     * @throws IOException I/O 异常
     */
    public String execute() throws IOException {
        Response response = okHttpClient.newCall(pidRequest.build(clientId, secret)).execute();
        if (response.isSuccessful()) {
            return Objects.requireNonNull(response.body()).string();
        } else {
            throw new DataReportClientException(
                "Response Code : " + response.code() + ", Response Message : " + response.message());
        }
    }

}
